﻿using PGMHelper;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;

namespace HystereticBasic
{
    /// <summary>
    /// 基本数据类
    /// 基本变量与构造函数
    /// </summary>
    public class BasicData
    {
        #region Variables

        /// <summary>
        /// 原始的力位移曲线
        /// </summary>
        public ForceDispObj OriginalCurveObj { set; get; }

        /// <summary>
        /// 骨架曲线对象
        /// </summary>
        private SkeletonSOE SkeletonCurveObj { set; get; }

        /// <summary>
        /// 数值骨架曲线
        /// </summary>
        private SkeletonSOE NumericalSkeletonCurveObj { set; get; }

        /// <summary>
        /// 滞回环集合
        /// </summary>
        public CycleSet CircleSet { set; get; }

        /// <summary>
        /// 平滑的滞回曲线
        /// </summary>
        private CycleSet SmoothCycleSet { set; get; }

        /// <summary>
        /// 数值滞回曲线
        /// </summary>
        private CycleSet NumericalCycleSet { set; get; }

        /// <summary>
        /// 文件路径
        /// </summary>
        protected string FilePath { set; get; }

        /// <summary>
        /// 绘图时对应的颜色
        /// </summary>
        public Color PosDataColor { set; get; }

        /// <summary>
        /// 绘图时对应的颜色
        /// </summary>
        public Color NegDataColor { set; get; }

        #endregion

        #region Properties

        /// <summary>
        /// 文件名
        /// </summary>
        public string FileName
        {
            get
            {
                return Path.GetFileNameWithoutExtension(this.FilePath);
            }
        }

        /// <summary>
        /// 是否位移响应数据
        /// </summary>
        private bool isDrift
        {
            get
            {
                //判断响应最大值是否小于1
                return Math.Max(Math.Abs(this.OriginalCurveObj.DispMinPoint.Disp),
                    this.OriginalCurveObj.DispMaxPoint.Disp) < 1;
            }
        }

        /// <summary>
        /// X坐标描述
        /// </summary>
        private string XAxisDescp
        {
            get
            {
                return this.isDrift ? "位移角" : "位移";
            }
        }

        #endregion

        /// <summary>
        /// 获得数据
        /// </summary>
        /// <param name="dataType"></param>
        /// <returns></returns>
        public List<float> this[DataType dataType]
        {
            get
            {
                return this.GetValueList(dataType, false);
            }
        }

        /// <summary>
        /// 获得数据
        /// </summary>
        /// <param name="dataType"></param>
        /// <returns></returns>
        public List<float> this[DataType dataType, bool isPos]
        {
            get
            {
                return this.GetDirectionValueList(dataType, isPos, false);
            }
        }

        /// <summary>
        /// 获得数据
        /// </summary>
        /// <param name="dataType"></param>
        /// <param name="isFilter"></param>
        /// <returns></returns>
        public List<float> GetValueList(DataType dataType, bool isFilter)
        {
            switch (dataType)
            {
                //滞回曲线位移
                case DataType.CyclicDisps: return this.OriginalCurveObj.Disps;
                //滞回曲线力
                case DataType.CyclicForces: return this.OriginalCurveObj.Forces;

                //平滑滞回曲线
                case DataType.SmoothCyclicDisps:
                    return this.SmoothCycleSet.Disps(true);
                case DataType.SmoothCyclicForces:
                    return this.SmoothCycleSet.Forces(true);
                case DataType.SmoothCyclicOrders:
                    return this.SmoothCycleSet.Orders(true).ConvertAll(f => (float)f);

                //数值滞回曲线
                case DataType.NumericalCyclicDisps:
                    return this.NumericalCycleSet.Disps(false);
                case DataType.NumericalCyclicForces:
                    return this.NumericalCycleSet.Forces(false);

                //滞回环相关
                case DataType.CycleMaxDisp:
                case DataType.AbsCycleMaxDisp:
                case DataType.AccumulateEnergy:
                case DataType.ViscousDampingRatio:
                case DataType.SecantStiffness:
                case DataType.SecantStiffnessRatio:
                case DataType.CycleIndex:
                case DataType.AbsUnloadDisp:
                case DataType.UnloadDispRatio:
                case DataType.UnloadDisp:
                case DataType.CycleMaxForce:
                case DataType.AbsCycleMaxForce:
                case DataType.CycleMaxForceRatio:
                    return this.CircleSet.GetValueList(dataType, isFilter);
                //骨架相关
                case DataType.SkeletonDisps:
                case DataType.SkeletonForces:
                case DataType.SkeletonOrder:
                    return this.SkeletonCurveObj.GetValueList(dataType);
                case DataType.NumericalSkeletonDisps:
                case DataType.NumercalSkeletonForces:
                    return this.NumericalSkeletonCurveObj.GetValueList(dataType);
                //加载历史
                case DataType.PositiveLoadingDisp: return this[DataType.CycleMaxDisp, true];
                case DataType.NegativeLoadingDisp: return this[DataType.CycleMaxDisp, false];
                //未知
                default: return new List<float>();
            }
        }

        /// <summary>
        /// 获得数据
        /// </summary>
        /// <param name="dataType"></param>
        /// <param name="isFilter"></param>
        /// <returns></returns>
        public List<float> GetDirectionValueList(DataType dataType, bool isPos, bool isFilter)
        {
            switch (dataType)
            {
                //滞回环相关
                case DataType.CycleMaxDisp:
                case DataType.AbsCycleMaxDisp:
                case DataType.AccumulateEnergy:
                case DataType.ViscousDampingRatio:
                case DataType.SecantStiffness:
                case DataType.SecantStiffnessRatio:
                case DataType.CycleIndex:
                case DataType.AbsUnloadDisp:
                case DataType.UnloadDispRatio:
                case DataType.UnloadDisp:
                case DataType.CycleMaxForce:
                case DataType.AbsCycleMaxForce:
                case DataType.CycleMaxForceRatio:
                    return this.CircleSet.GetValueList(dataType, isPos, isFilter);
                //骨架相关
                case DataType.SkeletonDisps:
                case DataType.SkeletonForces:
                case DataType.SkeletonOrder:
                    return this.SkeletonCurveObj.GetValueList(dataType, isPos);

                case DataType.NumericalSkeletonDisps:
                case DataType.NumercalSkeletonForces:
                    return this.NumericalSkeletonCurveObj.GetValueList(dataType, isPos);

                //未知
                default: return this[dataType];
            }
        }

        /// <summary>
        /// 获得表格数据
        /// </summary>
        public GridViewDatas GetData()
        {
            return this.GetData(new List<DataType> {
                //原始力位移曲线
                DataType.CyclicDisps, DataType.CyclicForces,
                 //骨架曲线
                DataType.SkeletonDisps, DataType.SkeletonForces,DataType.SkeletonOrder,
                //数值骨架曲线
                DataType.NumericalSkeletonDisps, DataType.NumercalSkeletonForces,
                //平滑滞回曲线
                DataType.SmoothCyclicDisps, DataType.SmoothCyclicForces,
                DataType.SmoothCyclicOrders,
                //数值骨架曲线
                DataType.NumericalCyclicDisps, DataType.NumericalCyclicForces,
                //滞回环序号
                DataType.CycleIndex,
                //增加加载历史
                DataType.PositiveLoadingDisp, DataType.NegativeLoadingDisp,
                //其他
                DataType.AbsCycleMaxDisp, DataType.AccumulateEnergy,
                DataType.ViscousDampingRatio,
                DataType.SecantStiffness,
                DataType.SecantStiffnessRatio
            });
        }

        /// <summary>
        /// 获得表格数据
        /// </summary>
        /// <param name="dataList"></param>
        /// <returns></returns>
        public GridViewDatas GetData(List<DataType> dataList)
        {
            //构造数据
            var data = new GridViewDatas(this.FileName);
            //遍历数据
            dataList.ForEach(dataType =>
            {
                data.Add(new GridViewColumn(this[dataType], demical: HystereticHelper.GetDemical(dataType),
                    titleName: this.FileName + "_" + HystereticHelper.GetDescp(dataType)));
            });
            //返回数据
            return data;
        }

        /// <summary>
        /// 获得表格数据
        /// </summary>
        /// <param name="dataList"></param>
        /// <param name="isPos"></param>
        /// <returns></returns>
        public GridViewDatas GetData(List<DataType> dataList, 
            bool isPosNegSeperate, bool isFilter)
        {
            //构造数据
            var data = new GridViewDatas(this.FileName);
            //函数指针
            Action<bool> addData = (isPos) =>
            {
                //遍历数据
                dataList.ForEach(dataType =>
                {
                    //精度
                    var demical = HystereticHelper.GetDemical(dataType);
                    var titleName = this.FileName + (isPos ? "_Pos" : "_Neg")
                    + HystereticHelper.GetDescp(dataType);
                    data.Add(new GridViewColumn(this.GetDirectionValueList(dataType, isPos, isFilter),
                        demical: demical, titleName: titleName));
                });
            };
            //判断类型
            if(isPosNegSeperate)
            {
                addData(true); addData(false);
            }
            else
            {
                //遍历数据
                dataList.ForEach(dataType =>
                {
                    //精度
                    var demical = HystereticHelper.GetDemical(dataType);
                    var posTitileName = this.FileName + "_" +
                    HystereticHelper.GetDescp(dataType);
                    data.Add(new GridViewColumn(this.GetValueList(dataType, isFilter),
               demical: demical, titleName: posTitileName));
                });
            }
            //返回数据
            return data;
        }

        /// <summary>
        /// 获得骨架数据
        /// </summary>
        /// <param name="isPos"></param>
        /// <returns></returns>
        public MontForceDispObj GetSkeletonObj(bool isPos)
        {
            return this.SkeletonCurveObj.GetSkeletonObj(isPos);
        }

        #region ToChart

        /// <summary>
        /// 绘制分解的滞回环
        /// </summary>
        /// <param name="chart"></param>
        public void CircleToChart(Chart chart, DataGridView grid, bool isFilter, bool isNorminal)
        {
            chart.SetTitle(TiltleType.Header, this.FileName);
            this.CircleSet.CircleToChart(chart, isFilter);
            grid.AddDatas(this.CircleSet.GetData(this.FileName, isNorminal));
        }

        /// <summary>
        /// 绘制骨架数据
        /// </summary>
        /// <param name="chart"></param>
        public void ToSkeletonChart(Chart chart)
        {
            //清空序列
            chart.Series.Clear();
            //设定图像图名
            chart.SetTitle(TiltleType.Header, string.Format("{0}力{1}曲线", this.FileName, this.XAxisDescp));
            //修改X轴坐标名称
            chart.SetTitle(TiltleType.AxisX, this.XAxisDescp);
            //绘制曲线
            this.OriginalCurveObj.ToChart(chart, "原始滞回曲线", Color.Red, 1);
            this.SkeletonCurveObj.ToChart(chart);
        }

        /// <summary>
        /// 数值骨架曲线
        /// </summary>
        /// <param name="chart"></param>
        public void ToNumericalSkeletonChart(Chart chart)
        {
            //清空序列
            chart.Series.Clear();
            //设定图像图名
            chart.SetTitle(TiltleType.Header, string.Format("{0}力{1}曲线", this.FileName, this.XAxisDescp));
            //修改X轴坐标名称
            chart.SetTitle(TiltleType.AxisX, this.XAxisDescp);
            //绘制曲线
            this.OriginalCurveObj.ToChart(chart, "原始滞回曲线", Color.Red, 1);
            this.NumericalSkeletonCurveObj.ToChart(chart);
        }

        /// <summary>
        /// 绘制平滑滞回曲线
        /// </summary>
        /// <param name="chart"></param>
        public void ToSmoothCyclesChart(Chart chart)
        {
            //清空序列
            chart.Series.Clear();
            //设定图像图名
            chart.SetTitle(TiltleType.Header, string.Format("{0}平滑力{1}曲线", this.FileName, this.XAxisDescp));
            //修改X轴坐标名称
            chart.SetTitle(TiltleType.AxisX, this.XAxisDescp);
            //绘制曲线
            this.OriginalCurveObj.ToChart(chart, "原始滞回曲线", Color.Red, 1);
            //平滑曲线
            this.SmoothCycleSet.CycleSetToChart(chart, Color.Blue, 3, false);
        }

        /// <summary>
        /// 绘制数值滞回曲线
        /// </summary>
        /// <param name="chart"></param>
        public void ToNumericalCyclesChart(Chart chart)
        {
            //清空序列
            chart.Series.Clear();
            //设定图像图名
            chart.SetTitle(TiltleType.Header, string.Format("{0}平滑力{1}曲线", this.FileName, this.XAxisDescp));
            //修改X轴坐标名称
            chart.SetTitle(TiltleType.AxisX, this.XAxisDescp);
            //绘制曲线
            this.OriginalCurveObj.ToChart(chart, "原始滞回曲线", Color.Red, 1);
            //平滑曲线
            this.NumericalCycleSet.CycleSetToChart(chart, Color.Blue, 3, false);
        }

        /// <summary>
        /// 滞回参数导出
        /// </summary>
        /// <param name="chart"></param>
        /// <param name="dataType"></param>
        /// <param name="isPosNegSeperate"></param>
        public void CycleDetailToChart(Chart chart, DataType dataType, 
            bool isPosNegSeperate, bool isFilter)
        {
            //添加序列
            Action<string, bool, Color> toChart = (tiltle,isPos, color) =>
            {
                //响应
                var valueList = isPosNegSeperate ?
                this.GetDirectionValueList(dataType, isPos, isFilter) :
                this.GetValueList(dataType, isFilter);
                //滞回序号
                var cyclicList = isPosNegSeperate ?
                this.GetDirectionValueList(DataType.CycleIndex, isPos, isFilter) :
                this.GetValueList(DataType.CycleIndex, isFilter);
                //创建序列
                chart.AddSeries(tiltle, SeriesChartType.Line, color);
                chart.AddSeries(tiltle + "P", SeriesChartType.Point, color, 2);
                //散点图例不可见
                chart.Series[tiltle + "P"].IsVisibleInLegend = false;
                //增加数据
                chart.Series[tiltle].Points.DataBindXY(cyclicList, valueList);
                chart.Series[tiltle + "P"].Points.DataBindXY(cyclicList, valueList);
            };
            //需要分离
            if(isPosNegSeperate)
            {
                toChart(this.FileName + "_Pos", true, this.PosDataColor);
                toChart(this.FileName + "_Neg", false, this.NegDataColor);
            }
            else toChart(this.FileName, true, this.PosDataColor);
        }

        #endregion

        /// <summary>
        /// 设定基础数据
        /// </summary>
        protected void SetBasicInformation(SkeletonSoftenMethod method)
        {
            //定义滞回环列表
            this.CircleSet = new CycleSet(this.OriginalCurveObj);
            //定义骨架曲线
            this.SkeletonCurveObj = new SkeletonSOE(this.CircleSet, method);
            //数值骨架曲线
            this.NumericalSkeletonCurveObj = this.SkeletonCurveObj.GetNumericalSkeleton();
            //滞回环平滑
            this.SmoothCycleSet = this.CircleSet.GetSmoothCycleSet();
            //滞回环数值化
            this.NumericalCycleSet = this.CircleSet.GetNumericalCycleSet();
        }

        #region 构造函数

        /// <summary>
        /// 获得数据
        /// </summary>
        /// <param name="skipLine"></param>
        /// <param name="isDispCtrl"></param>
        public static BasicData GetBasicData(int skipLine, 
            SkeletonSoftenMethod method = SkeletonSoftenMethod.ModEnvelope)
        {
            string filePath = string.Empty;
            if (!WilsonHelper.OpenFile("文本文件|*.txt|所有文件类型|*.*", ref filePath))
                return null;
            return new BasicData(filePath, skipLine, method);
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="OriginalDispList"></param>
        /// <param name="OriginalForceList"></param>
        public BasicData(List<ForceDispBasicPair> originalcurve,
            SkeletonSoftenMethod method = SkeletonSoftenMethod.ModEnvelope)
        {
            //初始化
            this.OriginalCurveObj = new ForceDispObj(originalcurve);
            //设定基础数据
            this.SetBasicInformation(method);
        }

        /// <summary>
        /// 构造滞回数据
        /// </summary>
        /// <param name="dispList"> 位移数据点 </param>
        /// <param name="forceList"> 力数据点 </param>
        /// <param name="method"> 骨架软化段定义方法 </param>
        public BasicData(List<float> dispList, List<float> forceList, 
            SkeletonSoftenMethod method = SkeletonSoftenMethod.ModEnvelope)
        {
            //初始化
            this.OriginalCurveObj = new ForceDispObj(dispList, forceList);
            //设定基础数据
            this.SetBasicInformation(method);
        }

        /// <summary>
        /// 构造滞回数据
        /// </summary>
        /// <param name="filePath"> 滞回数据文件路径 </param>
        /// <param name="skipLine"> 跳过行数 </param>
        /// <param name="isDispCtrl"> 骨架取滞回环位移最大点，否则取力最大点 </param>
        /// <param name="isFilter"> 是否过滤等位移滞回环（仅保留第一滞回环） </param>
        public BasicData(string filePath, int skipLine, 
            SkeletonSoftenMethod method = SkeletonSoftenMethod.ModEnvelope)
        {
            //初始化
            this.OriginalCurveObj = new ForceDispObj(filePath, skipLine);
            //设定基础数据
            this.SetBasicInformation(method);
            //获得文件路径
            this.FilePath = filePath;
        }

        /// <summary>
        /// 无参构造函数
        /// </summary>
        private BasicData()
        {
            //初始化
            this.OriginalCurveObj = new ForceDispObj();
        }

        #endregion

    }
}
